#ifndef _TWOGRE_WINDOW_H_
#define _TWOGRE_WINDOW_H_

#include <map>

#include "TwOgrePrerequisites.h"

#include "TwOgreVariable.h"
#include "TwOgreBoolVariable.h"
#include "TwOgreColorVariable.h"
#include "TwOgreEnumVariable.h"
#include "TwOgreIntegerVariable.h"
#include "TwOgreRealVariable.h"
#include "TwOgreStringVariable.h"
#include "TwOgreButtonVariable.h"
#include "TwOgreSeparatorVariable.h"
#include "TwOgreDirection3DVariable.h"
#include "TwOgrePosition3DVariable.h"
#include "TwOgreQuaternionVariable.h"

#include "OgreColourValue.h"
#include "OgreQuaternion.h"
#include "OgreString.h"
#include "OgreVector3.h"
#include "OgreVector2.h"
#include "OgreVector4.h"

namespace TwOgre{
	/**
	 * Window Class.
	 * This is the class that describes the actual window on the screen.  It's job
	 * is to create, contain, manage and destroy variables.
	 */
    class WindowParams
    {
    public:
        WindowParams(const Ogre::String& name)
            : name_(name)
            , title_(Ogre::StringUtil::BLANK)
            , color_(Ogre::ColourValue::ZERO)
            , help_(Ogre::StringUtil::BLANK)
            , width_(0)
            , height_(0)
            , x_(0)
            , y_(0)
            , valuesWidth_(0)
        {}
     
        WindowParams& title(const Ogre::String& varTitle)
        {
            title_ = varTitle;
            return *this;
        }
        WindowParams& color(const Ogre::ColourValue& varColor)
        {
            color_ = varColor;
            return *this;
        }
        WindowParams& help(const Ogre::String& varHelp)
        {
            help_ = varHelp;
            return *this;
        }
        WindowParams& width(const int& width)
        {
            width_ = width;
            return *this;
        }
        WindowParams& valuesWidth(const int& width)
        {
            valuesWidth_ = width;
            return *this;
        }
        WindowParams& height(const int& height)
        {
            height_ = height;
            return *this;
        }
        WindowParams& size(const int& width, const int& height)
        {
            width_ = width;
            height_ = height;
            return *this;
        }
        WindowParams& size(const Ogre::Vector2& sizeVect)
        {
            width_ = static_cast<int>(sizeVect.x);
            height_ = static_cast<int>(sizeVect.y);
            return *this;
        }
        WindowParams& position(const int& x, const int& y)
        {
            x_ = x;
            y_ = y;
            return *this;
        }
        WindowParams& position(const Ogre::Vector2& pos)
        {
            x_ = static_cast<int>(pos.x);
            y_ = static_cast<int>(pos.y);
            return *this;
        }
        WindowParams& area(const Ogre::Vector4& windowArea)
        {
            x_ = static_cast<int>(windowArea.w);
            y_ = static_cast<int>(windowArea.x);
            width_ = static_cast<int>(windowArea.y);
            height_ = static_cast<int>(windowArea.z);
            return *this;
        }
        WindowParams& area(int x, int y, int width, int height)
        {
            x_ = x;
            y_ = y;
            width_ = width;
            height_ = height;
            return *this;
        }
    private:
        Ogre::String name_;
        Ogre::String title_;
        Ogre::ColourValue color_;
        Ogre::String help_;
        int width_;
        int height_;
        int x_;
        int y_;
        int valuesWidth_;

        friend class WindowManager;
		friend class Window;		
    };
	
    class TwOgreExport Window
	{
	protected:
		/**
		* Constructor.
		* This constructor is protected because you should only ever construct a Window
		* through the WindowManager::createWindow() method.
		*/
		Window(const Ogre::String& name, const Ogre::String& title, 
				const Ogre::ColourValue& windowColor, const Ogre::String& help);
		Window(WindowParams& params);
		/** Standard Destructor */
		~Window();

	public:
		/** Shows the Window. */
		void show();
		/** Hides the Window. */
		void hide();
		/** Minimizes the Window to a small icon in the lower left corner of the screen. */
		void iconify();

		/** Sets the background color for the Window. */
		void setColor(const Ogre::ColourValue& color);
		/** Sets the string that describes the Window in the Help Window. */
		void setHelp(const Ogre::String& help);
		/** Sets the Window position */
		void setPosition(const Ogre::Vector2& position);
		/** Sets the Window position */
		void setPosition(int x, int y);
		/** Sets the Window size */
		void setSize(const Ogre::Vector2& size);
		/** Sets the Window size */
		void setSize(int width, int height);
		/** Sets the Window position and size */
		void setWindowArea(const Ogre::Vector4& windowArea);
		/** Sets the Window position and size */
		void setWindowArea(int x, int y, int width, int height);
		/** Sets the text in the title bar of the Window */
		void setTitle(const Ogre::String& title);
		/** Sets the width of the area allowed for the Variables in the Window. */
		void setValuesWidth(int width);
        /** Refreshes the window */
        void refresh();
		
        /** Returns the name of the Window */
		const Ogre::String& getName() {return mName;}

		/** Adds a Separator widget to the window. */
		SeparatorVariable* addSeparator(const Ogre::String& name, const Ogre::String& groupName = "", const Ogre::String& def = "");
		SeparatorVariable* addSeparator(SeparatorParams& params);
		/** Adds a Button widget to the window. */
		ButtonVariable* addButton(const Ogre::String& name, const Ogre::String& label = "", const Ogre::String& groupName = "", const Ogre::String& help="", TwButtonCallback  callback = NULL, void* data = NULL, const Ogre::String& def = "");
		ButtonVariable* addButton(ButtonParams& params);
		/** Adds a BoolVariable widget to the window. */
		BoolVariable* addBoolVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			bool value=false, const Ogre::String& groupName="", const Ogre::String& help="");
		BoolVariable* addBoolVariable(BoolParams& params);
		/** Adds a ColorVariable widget to the window. */
		ColorVariable* addColorVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			const Ogre::ColourValue& color=Ogre::ColourValue::Black,
			const Ogre::String& groupName="", const Ogre::String& help="");
		ColorVariable* addColorVariable(ColorParams& params);
		/** Adds a Direction3DVariable widget to the window. */
		Direction3DVariable* addDirection3DVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			const Ogre::Vector3& vector=Ogre::Vector3::ZERO,
			const Ogre::String& groupName="", const Ogre::String& help="");
		Direction3DVariable* addDirection3DVariable(Direction3DParams& params);
		Position3DVariable* addPosition3DVariable(const Ogre::String& name, bool readOnly, const Ogre::String& label, 
			Ogre::Vector3 value, const Ogre::String& groupName, const Ogre::String& help);
		Position3DVariable* addPosition3DVariable(Position3DParams& params);
		/** Adds a QuaternionVariable widget to the window. */
		QuaternionVariable* addQuaternionVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			const Ogre::Quaternion& quat=Ogre::Quaternion::ZERO,
			const Ogre::String& groupName="", const Ogre::String& help="");
		QuaternionVariable* addQuaternionVariable(QuaternionParams& params);
		/** Adds an EnumVariable widget to the window. */
		EnumVariable* addEnumVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			const EnumValueList& enumList=EnumValueList(), int value=0, const Ogre::String& groupName="", const Ogre::String& help="");
		EnumVariable* addEnumVariable(EnumParams& params);
		/** Adds a IntegerVariable widget to the window. */
		IntegerVariable* addIntegerVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			int value=0, const Ogre::String& groupName="", const Ogre::String& help="");
		IntegerVariable* addIntegerVariable(IntegerParams& params);
		/** Adds a RealVariable widget to the window. */
		RealVariable* addRealVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			Ogre::Real value=0.0, const Ogre::String& groupName="", const Ogre::String& help="");
		RealVariable* addRealVariable(RealParams& params);
		/** Adds a RealVariable widget to the window. */
		StringVariable* addStringVariable(const Ogre::String& name, bool readOnly=false, const Ogre::String& label="", 
			const Ogre::String& value="", const Ogre::String& groupName="", const Ogre::String& help="");
		StringVariable* addStringVariable(StringParams& params);

	protected:
		/** Return a pointer to the underlying AntTweakBar */
		TwBar* getTweakBar() {return mTweakBar;}

	private:
		TwBar *mTweakBar;
		Ogre::String mName;

		typedef std::map<Ogre::String, Variable*> VariableMap;
		VariableMap mVariableMap;

		friend class WindowManager;
		friend class Variable;
		friend class BoolVariable;
		friend class ColorVariable;
		friend class EnumVariable;
		friend class IntegerVariable;
		friend class RealVariable;
		friend class StringVariable;		
		friend class ButtonVariable;		
		friend class SeparatorVariable;
		friend class QuaternionVariable;
		friend class Direction3DVariable;
        friend class Position3DVariable;
    };
}; // End Namespace

#endif
